using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using FernUniHagen.CompilerExtension.DataStructures;
using FernUniHagen.CompilerExtension.Values;
using Roslyn.Compilers.Common;
using Roslyn.Compilers.CSharp;
using FernUniHagen.CompilerExtension.Functions;
using FernUniHagen.CompilerExtension.Interfaces;

namespace FernUniHagen.CompilerExtension.Adaptor
{
    public abstract class SyntaxElementFactory
    {
        
        /// <summary>
        /// GetInstance decides which adaptor shall be taken
        /// </summary>
        protected SyntaxElementFactory()
        {

        }


        /// <summary>
        /// Gets the IDeclaration Interface for the Nodes FieldDeclaration, MethodDeclaration, ParameterSyntax and PropertyDeclaration.
        /// Those fields have in common that they can have a type and an annotation (a common thing that was not recognized by the roslyn developers)
        /// Adaptor classes inherit the common interface
        /// </summary>
        /// <param name="node">A common syntaxnode, either a Field, a Method,  a Parameter or a Property</param>
        /// <returns>the proper adaptor class which provides the required interface</returns>
        public static IDeclaration<CommonSyntaxNode> GetDeclaration(CommonSyntaxNode node, ISemanticModel model)
        {
            IDeclaration<CommonSyntaxNode> declaration = null;
            if (node is PropertyDeclarationSyntax)
                declaration = new PropertyDeclarationAdaptor(model, node as PropertyDeclarationSyntax);
            else if (node is MethodDeclarationSyntax)
                declaration = new MethodDeclarationAdaptor(model, node as MethodDeclarationSyntax);
            else if (node is ParameterSyntax)
                declaration = new ParameterDeclarationAdaptor(model, node as ParameterSyntax);
            else if (node is FieldDeclarationSyntax)
                declaration = new FieldDeclarationAdapter(model, node as FieldDeclarationSyntax);
            else if (node is VariableDeclarationSyntax)
                declaration = new VariableDeclarationAdaptor(model, node as VariableDeclarationSyntax);
            declaration.SemanticModel = model;
            return declaration;
        }

        /// <summary>
        /// Gets an object of the class which is responsible for the conversion. 
        /// </summary>
        /// <param name="semanticModel">Semantik model of the document where the node to replace is in</param>
        /// <param name="nodeToReplace">the node which needs to replace</param>
        /// <param name="nodeInfos">in case the node to replace is a block, a list of nodes which needs to be replaced is added. If we do not deal with a block
        /// this can be null</param>
        /// <returns>an object of the class which is responsible for the conversion</returns>
        public static IMultiplicityConvertible<CommonSyntaxNode> GetConverter(ISemanticModel semanticModel, CommonSyntaxNode nodeToReplace, SyntaxNodeInfo nodeInfo = null)
        {
            IMultiplicityConvertible<CommonSyntaxNode> convertibleObject = null;
            if (nodeToReplace is PropertyDeclarationSyntax)
                convertibleObject = new PropertyDeclarationAdaptor(semanticModel, nodeToReplace as PropertyDeclarationSyntax);
            else if (nodeToReplace is MethodDeclarationSyntax)
           //     convertibleObject = new BlockSyntaxAdapter(nodeToReplace as BlockSyntax, semanticModel, nodeInfos);
               convertibleObject = new MethodDeclarationAdaptor(semanticModel, nodeToReplace as MethodDeclarationSyntax );
            else if (nodeToReplace is ParameterSyntax)
                convertibleObject = new ParameterDeclarationAdaptor(semanticModel, nodeToReplace as ParameterSyntax );
            else if (nodeToReplace is FieldDeclarationSyntax)
                convertibleObject = new FieldDeclarationAdapter(semanticModel, nodeToReplace as FieldDeclarationSyntax);
            else if (nodeToReplace is BlockSyntax)
                convertibleObject = new BlockSyntaxAdapter(nodeToReplace as BlockSyntax, semanticModel, nodeInfo);
            //    convertibleObject = new BlockSyntaxConverter(semanticModel, nodeInfos);
            //Class Declaration is probably not needed. was the first approach for linq statements (Inherit from IEnumerable)
            else if (nodeToReplace is ClassDeclarationSyntax)
                return null;
            else
                convertibleObject = new DefaultBlockNode(nodeToReplace);
            return convertibleObject;
        }

    }
}
